﻿Imports Microsoft.AspNet.Identity
Imports System.Data.Entity.Validation
Imports System.Linq
Imports System.Security.Claims
Imports System.Threading.Tasks

Public Class RegisterExternalLogin
    Inherits System.Web.UI.Page
    Public Property ProviderName() As String
        Get
            Return If(DirectCast(ViewState("ProviderName"), String), [String].Empty)
        End Get
        Private Set(value As String)
            ViewState("ProviderName") = value
        End Set
    End Property

    Public Property ProviderAccountKey() As String
        Get
            Return If(DirectCast(ViewState("ProviderAccountKey"), String), [String].Empty)
        End Get
        Private Set(value As String)
            ViewState("ProviderAccountKey") = value
        End Set
    End Property

    Private Async Function RegisterExternalLoginAsync() As Task
        Dim id As ClaimsIdentity = Await Context.GetExternalIdentity()
        If id Is Nothing Then
            ModelState.AddModelError("", "There was an error processing this request.")
            Return
        End If

        ' Make sure the external identity is from the loginProvider we expect
        Dim providerKeyClaim As Claim = id.FindFirst(ClaimTypes.NameIdentifier)
        If providerKeyClaim Is Nothing OrElse providerKeyClaim.Issuer <> ProviderName Then
            ModelState.AddModelError("", "There was an error processing this request.")
            Return
        End If

        ' Succeeded so we should be able to lookup the local user name and sign them in
        ProviderAccountKey = providerKeyClaim.Value
        Dim localUserName As String = IdentityConfig.Logins.GetUserId(ProviderName, ProviderAccountKey)
        If Not [String].IsNullOrEmpty(localUserName) Then
            Context.SignIn(localUserName, id.Claims, isPersistent:=False)
            IdentityConfig.RedirectToReturnUrl(Request.QueryString("ReturnUrl"), Response)
        Else
            ' No local user for this account
            If User.Identity.IsAuthenticated Then
                ' If the current user is logged in, just add the new account
                IdentityConfig.Logins.Add(New UserLogin(User.Identity.GetUserId(), ProviderName, ProviderAccountKey))
                IdentityConfig.RedirectToReturnUrl(Request.QueryString("ReturnUrl"), Response)
            Else
                userName.Text = id.Name
            End If
        End If
    End Function

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ' Process the result from an auth provider in the request
        ProviderName = IdentityConfig.GetProviderNameFromRequest(Request)

        If [String].IsNullOrEmpty(ProviderName) Then
            Response.Redirect("/Account/Login")
        End If

        If Not IsPostBack Then
            RegisterAsyncTask(New System.Web.UI.PageAsyncTask(AddressOf RegisterExternalLoginAsync))
        End If
    End Sub

    Protected Sub logIn_Click(sender As Object, e As EventArgs)
        CreateAndLoginUser()
    End Sub

    Protected Sub cancel_Click(sender As Object, e As EventArgs)
        IdentityConfig.RedirectToReturnUrl(Request.QueryString("ReturnUrl"), Response)
    End Sub

    Private Async Function CreateAndLoginUserAsync() As Task
        Dim id As ClaimsIdentity = Await Context.GetExternalIdentity()
        If id Is Nothing Then
            ModelState.AddModelError("", "There was an error processing this request.")
            Return
        End If
        Try
            Dim user As New User(userName.Text)
            If IdentityConfig.Users.Create(user) Then
                IdentityConfig.Logins.Add(New UserLogin(user.Id, ProviderName, ProviderAccountKey))
                Context.SignIn(user.Id, id.Claims, isPersistent:=False)
                IdentityConfig.RedirectToReturnUrl(Request.QueryString("ReturnUrl"), Response)
            End If
        Catch e As DbEntityValidationException
            ModelState.AddModelError("", e.EntityValidationErrors.First().ValidationErrors.First().ErrorMessage)
        End Try
    End Function

    Private Sub CreateAndLoginUser()
        If Not IsValid Then
            Return
        End If

        RegisterAsyncTask(New System.Web.UI.PageAsyncTask(AddressOf CreateAndLoginUserAsync))
    End Sub

End Class